#ifndef IO_H
#define IO_H

#include "param.h"
#include "serialportobj.h"
#include "utility.h"
#include <QBitArray>
#include <QDebug>
#include <QObject>

#define INPUT_ONE  // UPDATE 选择输入IO使用情况：  INPUT_ONE INPUT_TWO
#define INPUT_8    // UPDATE 选择新增输入IO的位数：INPUT_8 INPUT_32

class IO : public QObject {
    Q_OBJECT
public:
    explicit IO( QObject* parent = nullptr );
    enum DiDefine {
        EMERGENCY_STOP = 0,                 //急停按钮
        ACTIVATE,                           //（启动/暂停）按钮
        ARRIVE_SIGNAL,                      //到位光电信号
        LEFT_SERVO_DRIVER_ALARM,            //左伺服报警
        RIGHT_SERVO_DRIVER_ALARM,           //右伺服报警
        UPPER_LEFT_DC_DRIVER_ALARM,         //上左直流驱动报警
        UPPER_RIGHT_DC_DRIVER_ALARM,        //上右直流驱动报警
        LOWER_LEFT_DC_DRIVER_ALARM,         //下左直流驱动报警
        LOWER_RIGHT_DC_DRIVER_ALARM,        //下右直流驱动报警
        BACK_OBSTACLE_SLOW_LAYER,           //后避障减速区域
        BACK_OBSTACLE_STOP_LAYER,           //后避障急停区域
        LEFT_OBSTACLE_STOP_LAYER,           //左避障急停区域
        RIGHT_OBSTACLE_STOP_LAYER,          //右避障急停区域
        FRONT_OBSTACLE_STOP_LAYER,          //（导航雷达）前避障急停区域
        FRONT_OBSTACLE_SLOW_LAYER,          //（导航雷达）前避障减速区域
        UL_SAFE_SIGNAL,                     //上左防掉料光感
        UL_1_SIGNAL,                        //上左光感1
        UL_2_SIGNAL,                        //上左光感2
        UL_3_SIGNAL,                        //上左光感3
        UL_4_SIGNAL,                        //上左光感4
        UL_5_SIGNAL,                        //上左光感5
        UR_SAFE_SIGNAL,                     //上右防掉料光感
        UR_1_SIGNAL,                        //上右光感1
        UR_2_SIGNAL,                        //上右光感2
        UR_3_SIGNAL,                        //上右光感3
        UR_4_SIGNAL,                        //上右光感4
        UR_5_SIGNAL,                        //上右光感5
        LL_SAFE_SIGNAL,                     //下左防掉料光感
        LL_1_SIGNAL,                        //下左光感1
        LL_2_SIGNAL,                        //下左光感2
        LL_3_SIGNAL,                        //下左光感3
        LL_4_SIGNAL,                        //下左光感4
        LL_5_SIGNAL,                        //下左光感5
        LR_SAFE_SIGNAL,                     //下右防掉料光感
        LR_1_SIGNAL,                        //下右光感1
        LR_2_SIGNAL,                        //下右光感2
        LR_3_SIGNAL,                        //下右光感3
        LR_4_SIGNAL,                        //下右光感4
        LR_5_SIGNAL,                        //下右光感5
        FORNT_ANTI_COLLISION,               //前防撞条急停触发
        BACK_ANTI_COLLISION,                //后防撞条急停触发
        UPPER_ROLLER_SHUTTER_DRIVER_ALARM,  //上层卷帘直流电机报警
        LOWER_ROLLER_SHUTTER_DRIVER_ALARM,  //下层卷帘直流电机报警
        UPPER_UPPER_LIMIT_SIGNAL,           //上层卷帘上限位光感
        UPPER_LOWER_LIMIT_SIGNAL,           //上层卷帘下限位光感
        LOWER_UPPER_LIMIT_SIGNAL,           //下层卷帘上限位光感
        LOWER_LOWER_LIMIT_SIGNAL,           //下层卷帘下限位光感

    };
    Q_ENUM( DiDefine )

    enum DoDefine {
        ACTIVATE_LED = 0,                       //启动按钮指示灯
        CHARGE,                                 //充电继电器
        RED_LED,                                //三色灯红色
        YELLOW_LED,                             //三色灯黄色
        GREEN_LED,                              //三色灯绿色
        UPPER_LEFT_DC_DRIVER_DIRECTION,         //上左直流驱动方向
        UPPER_LEFT_DC_DRIVER_ENABLE,            //上左直流驱动启停
        UPPER_RIGHT_DC_DRIVER_DIRECTION,        //上右直流驱动方向
        UPPER_RIGHT_DC_DRIVER_ENABLE,           //上右直流驱动启停
        LOWER_LEFT_DC_DRIVER_DIRECTION,         //下左直流驱动方向
        LOWER_LEFT_DC_DRIVER_ENABLE,            //下左直流驱动启停
        LOWER_RIGHT_DC_DRIVER_DIRECTION,        //下右直流驱动方向
        LOWER_RIGHT_DC_DRIVER_ENABLE,           //下右直流驱动启停
        BACK_OBSTACLE_INPUT_1,                  //后避障区域输入1
        BACK_OBSTACLE_INPUT_2,                  //后避障区域输入2
        LEFT_SERVO_DRIVER_ENABLE,               //左轮伺服驱动使能
        RIGHT_SERVO_DRIVER_ENABLE,              //右轮伺服驱动使能
        WORKING_MUSIC_1,                        //工作音乐1
        WORKING_MUSIC_2,                        //工作音乐2
        WORKING_MUSIC_3,                        //工作音乐3
        WORKING_MUSIC_4,                        //工作音乐4
        WORKING_MUSIC_5,                        //工作音乐5
        FRONT_OBSTACLE_INPUT_1,                 //（导航雷达）前避障区域输入1
        FRONT_OBSTACLE_INPUT_2,                 //（导航雷达）前避障区域输入2
        LEFT_YELLOW_LIGHT,                      //左转向黄灯
        RIGHT_YELLOW_LIGHT,                     //右转向黄灯
        LEFT_AND_RIGHT_BLLUE_LIGHT,             //左右蓝灯
        UPPER_ROLLER_SHUTTER_DRIVER_DIRECTION,  //上卷帘直流驱动方向
        UPPER_ROLLER_SHUTTER_DRIVER_ENABLE,     //上卷帘直流驱动启停
        LOWER_ROLLER_SHUTTER_DRIVER_DIRECTION,  //下卷帘直流驱动方向
        LOWER_ROLLER_SHUTTER_DRIVER_ENABLE,     //下卷帘直流驱动启停
        UPPER_ROLLER_SHUTTER_BREAK,             //上卷帘门电机刹车
        LOWER_ROLLER_SHUTTER_BREAK,             //下卷帘门电机刹车

    };
    Q_ENUM( DoDefine )
    enum IOState {
        SET = 0,
        RESET,
        TOGGLE,
    };

#ifdef INPUT_ONE
    enum IO_ADDRESS {
        IO_INPUT_1  = 1,  // IO输入模块1
        IO_OUTPUT_1 = 2,  // IO输出模块1
    };
#endif

#ifdef INPUT_TWO
    enum IO_ADDRESS {
        IO_INPUT_1  = 1,  // IO输入模块1
        IO_INPUT_2  = 2,  // IO输入模块1
        IO_OUTPUT_1 = 3,  // IO输出模块1
    };
#endif
    IOState getDi( DiDefine diIndex );              //公开输入io状态获取
    IOState getDo( DoDefine doIndex );              //公开输出io状态获取
    int getDiKeytoValue( DiDefine diIndex );        //从enum获取key再对表获取value
    int getDoKeytoValue( DoDefine doIndex );        //从enum获取key再对表获取value
    void setDo( DoDefine doIndex, IOState value );  //输出io状态设定
    void toggleDO( int id );                        //切换io状态
    void resetAllDo();                              //复位全部输出io,并选择是否关闭输出io的控制
    void breakHandler();                            //代码 崩溃失去控制而触发的特定io口
    void readIoState();
    void sendIoType();
    uint getIointputA();
    uint getIointputB();
    uint getIoOutput();

private:
    void       initData();                                //初始化数据
    QByteArray getIODataByAddress( IO_ADDRESS address );  //根据模块地址获取查询数据
    void ioControlSetIoState();                           //向io控制器发送命令设置输出io状态
    void ioSendData();

    SerialPortObj*       io_control_com = nullptr;                // IO模块串口
    QList< QByteArray >* sendDatas;                               //发送信息
    QBitArray            io_type_;                                // io的ui展示数目和类型                                                                             //读取输出IO模块1
    unsigned int         io_32in                   = 0x00000001;  //输入IO控制器的io 32位
    unsigned int         io_32in_2                 = 0x00000000;  //输入IO控制器的io 32位
    unsigned int         io_32out                  = 0x00000000;  //输出IO控制器的io 32位
    int                  input_1_lose_connect_time = 0, input_2_lose_connect_time = 0, output_1_lose_connect_time = 0;  //失去连接时间
    int                  sendIndex        = 0;                                                                          //发送信息下标
    bool                 is_allow_setting = true;

signals:
    void sigSendData( SerialPortObj* obj, const QByteArray& data );
    void sigSendTips( const QString& );
    void sigLoseConnect( const QString& );
    void sigSendIoState( const QBitArray& );
    void sigSendIoType( const QBitArray& );
    void sigIOReceiveData( QByteArray data, QString str );  //测试,界面显示io接收源数据
    void sigIoDefineStrError();
public slots:
    void sltIOInit();
    void slt50msTimer();
    void sltIORecvieData( const QByteArray& data );
    void sltToggleDoBit( int moduleId, int id );
};

#endif  // IO_H
